package com.zer0.tga;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;


//import com.Zer0.tga.Game;
import com.zer0.tga.art.Screen;
import com.zer0.tga.entity.livingentity.Teemo;
import com.zer0.tga.input.InputHandler;
import com.zer0.tga.input.Input;
import com.zer0.tga.level.Level;
import com.zer0.tga.level.Room;
import com.zer0.tga.math.Coordinate;
import com.zer0.tga.tile.Tile;
import com.zer0.tga.ui.IntroUi;
import com.zer0.tga.ui.Ui;

public class Game extends Canvas implements Runnable {
	
	private static Game game; //= new Game(); // singleton
	
	
	private static final int GAME_HEIGHT = Tile.HEIGHT*Room.ROOM_Y; // 64*9  = 576
	private static final int GAME_WIDTH = Tile.WIDTH*Room.ROOM_X;  // 64*13 = 832
	private static final int SCREEN_HEIGHT = 720;                
	private static final int SCREEN_WIDTH = 840;    
	private static final int HUD_HEIGHT = 90; //(SCREEN_WIDTH*3/4) - SCREEN_HEIGHT;			   	 	  // 90+576 = 666	
	private static double SCALE; 
	
	private boolean gameRunning = false;
	
	
	public Input input = new Input();
	
	public String fpsInfo = " ";
	
	private Level level;
	private Level bossLevel;
	
	private int levels[] = {0,4,12,18,20,26,28};
	private int currentLevel;
	
	private Ui ui;
	/*
    private Screen screen = new Screen((int)(SCREEN_WIDTH*SCALE), (int)(SCREEN_HEIGHT*SCALE));
    private Screen uiscreen = new Screen((int)(SCREEN_WIDTH*SCALE),(int)(UI_HEIGHT*SCALE));
	*/
	public Screen screen = new Screen(GAME_WIDTH, GAME_HEIGHT);
	public Screen hudscreen = new Screen(GAME_WIDTH,HUD_HEIGHT);
	public Screen uiscreen = new Screen(GAME_WIDTH, GAME_HEIGHT+HUD_HEIGHT);
	
 //   public boolean shouldRender;
    
    public Teemo teemo;
   
    private static boolean fullscreen = false;
    private static boolean stretch = false;
    private static boolean debug = false;
    
    
    
	/**
	 * 
	 */
	private static final long serialVersionUID = 7153991173738458627L;

	
	private Game() {

		InputHandler iHnd = new InputHandler(input);
		this.addKeyListener(iHnd);
		this.addMouseListener(iHnd);
		this.addMouseMotionListener(iHnd);
		
		//GameProperties.
		
		if(stretch)
		{
			if(fullscreen)
			{
				SCALE = ((double) Toolkit.getDefaultToolkit().getScreenSize().height / (GAME_HEIGHT+HUD_HEIGHT));
				input.mouseOffset_x = (int) (( Toolkit.getDefaultToolkit().getScreenSize().width - GAME_WIDTH*SCALE) / 2) ;
				input.mouseOffset_y = (int) (HUD_HEIGHT*SCALE); //(int) (( Toolkit.getDefaultToolkit().getScreenSize().height - (GAME_HEIGHT+HUD_HEIGHT)*SCALE)/ 2 + HUD_HEIGHT*SCALE);
			
				input.scale = SCALE;
				
			}
			else
			{
				SCALE = ((double)SCREEN_HEIGHT / (GAME_HEIGHT+HUD_HEIGHT));
				input.mouseOffset_x = (int) (( SCREEN_WIDTH - GAME_WIDTH)*SCALE / 2) ;
				input.mouseOffset_y = (int) (( SCREEN_HEIGHT - (GAME_HEIGHT+HUD_HEIGHT))*SCALE / 2 + HUD_HEIGHT*SCALE);
			
			}
			
		
			
		}
		else
		{
			SCALE = 1;
			
			if(fullscreen)
			{
				input.mouseOffset_x = (int) (( Toolkit.getDefaultToolkit().getScreenSize().width - GAME_WIDTH) / 2) ;
				input.mouseOffset_y = (int) (( Toolkit.getDefaultToolkit().getScreenSize().height - (GAME_HEIGHT+HUD_HEIGHT)) / 2 + HUD_HEIGHT);
			}
			else
			{
				input.mouseOffset_x = (int) ((SCREEN_WIDTH - GAME_WIDTH) / 2) ;
				input.mouseOffset_y = (int) ((SCREEN_HEIGHT - (GAME_HEIGHT+HUD_HEIGHT)) / 2 + HUD_HEIGHT);
			}
			
		}
		
		

		if(!fullscreen)
		{
		this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
		this.setMinimumSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
	    this.setMaximumSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
	    
	    
		}
		
	/*	System.out.println(SCALE);
		System.out.println(input.mouseOffset_x + " " + input.mouseOffset_y);
		*/
		
		// request the focus so key events come to us
		requestFocus();
		
	}
	
	public static void main(String argv[]) {
	
		argumentCheck(argv);
		
		//Game game = new Game();
		
		// create a frame to contain our game
		JFrame frame = new JFrame("Teemo's Great Adventure");
		//System.out.println(SCREEN_WIDTH+" "+SCREEN_HEIGHT+" "+GUI_HEIGHT+" "+SCALE);
		
		if(!fullscreen)
		{
			// add game to panel, add panel to frame
			JPanel panel = new JPanel(new BorderLayout());
			panel.add(Game.getInstance());
			frame.add(Game.getInstance());
			initFrame(frame);	
		}
		else
		{
			frame.add(Game.getInstance());
			frame.setUndecorated(true);
			initFrame(frame);
			// for fullscreen we create graphics device and environment
			GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
			GraphicsDevice gd = ge.getDefaultScreenDevice();
			//GraphicsConfiguration gc = gd.getDefaultConfiguration();

			gd.setFullScreenWindow( frame );
			if( gd.isDisplayChangeSupported() ) {
				DisplayMode dm = new DisplayMode(Toolkit.getDefaultToolkit().getScreenSize().width ,Toolkit.getDefaultToolkit().getScreenSize().height, 32, 60 );
				gd.setDisplayMode(dm);
			}	
		}
		
		// BEEP BOOP START THE GAME
		Game.getInstance().start();		
		
	}
	
	public static Game getInstance()
	{
		if(game == null)
			game = new Game();
		return game;
	}
	
	private static void argumentCheck(String[] argv) {
		
		for(String str:argv)
		{
			if(str.contentEquals("f"))
				fullscreen = true;
			else if(str.contentEquals("s"))
				stretch = true;
			else if(str.contentEquals("d"))
				debug = true;
		}
		
	}

	private void start() {
		gameRunning = true;
        Thread gameThread = new Thread(this);
        gameThread.setPriority(Thread.MAX_PRIORITY);
        gameThread.start();
    }
	
	
    public void stop() {
    	gameRunning = false;
       
    }
    
    public static void initFrame(JFrame frame)
    {
    	frame.pack();
		frame.setResizable(false);
	    frame.setLocationRelativeTo(null);
	    frame.setIgnoreRepaint(true);
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // alttaki yerine bu var?
		frame.setVisible(true);
    }


 //MOJAM RUN
    public void run6() {
        long lastTime = System.nanoTime();
        double unprocessed = 0;
        int frames = 0;
        long lastTimer1 = System.currentTimeMillis();

        int tickk= 0, loop=0;
        
        init();
        
        // TEST PURPOSES
        level.createLevel(20);
      
        
        
        // TEST PURPOSES END
        

        int toTick = 0;

        while (gameRunning) {
        	loop++;
            if (!this.hasFocus()) {
                input.release();
            }
            
            double nsPerTick = 1000000000.0 / 60;
            boolean shouldRender = false;
            //System.out.print(unprocessed + "-");
            while (unprocessed >= 1) {
                toTick++;
                unprocessed -= 1;
            }

            int tickCount = toTick;
            //System.out.println(tickCount);
            if (toTick > 0 && toTick < 3) {
                tickCount = 1;
            }
            if (toTick > 20) {
                toTick = 20;
            }

            for (int i = 0; i < tickCount; i++) {
                toTick--;
                //long before = System.nanoTime();
                tick();
                tickk++;
                //long after = System.nanoTime();
                //System.out.println("Tick time took " + (after - before) * 100.0 / nsPerTick + "% of the max time");
                shouldRender = true;
            }
//            shouldRender = true;

            BufferStrategy bs = getBufferStrategy();
            if (bs == null) {
                createBufferStrategy(3);
                //createBufferStrateg
                continue;
            }
            if (shouldRender) {
                frames++;
                Graphics g = bs.getDrawGraphics();
                render(g);
            }

            long now = System.nanoTime();
            unprocessed += (now - lastTime) / nsPerTick;
            lastTime = now;

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (shouldRender) {
                if (bs != null) {
                    bs.show();
                }
            }

            if (System.currentTimeMillis() - lastTimer1 > 1000) {
                lastTimer1 += 1000;
                fpsInfo = "FPS:" + frames + " Tick:" + tickk + " Loop:" + loop;
                System.out.println(fpsInfo);
                frames = 0;
                tickk = 0;
                loop = 0;
            }
        }
    }


    public void run()
    {
    	long lastTime = System.nanoTime();
        double unprocessed = 0;
        int frames = 0;
        long lastTimer1 = System.currentTimeMillis();

        int tickk= 0, loop=0;
        
        init();
        
    
        

        int toTick = 0;

        while (gameRunning) {
        	loop++;
            if (!this.hasFocus()) {
                input.release();
            }
            
            double nsPerTick = 1000000000.0 / 60;
            boolean shouldRender = false;
            //System.out.print(unprocessed + "-");
            while (unprocessed >= 1) {
                toTick++;
                unprocessed -= 1;
            }

            int tickCount = toTick;
            //System.out.println(tickCount);
            if (toTick > 0 && toTick < 3) {
                tickCount = 1;
            }
            if (toTick > 20) {
                toTick = 20;
            }

            for (int i = 0; i < tickCount; i++) {
                toTick--;
                //long before = System.nanoTime();
                tick();
                tickk++;
                //long after = System.nanoTime();
                //System.out.println("Tick time took " + (after - before) * 100.0 / nsPerTick + "% of the max time");
                shouldRender = true;
            }
//            shouldRender = true;

            BufferStrategy bs = getBufferStrategy();
            if (bs == null) {
                createBufferStrategy(3);
                //createBufferStrateg
                continue;
            }
            if (shouldRender) {
                frames++;
                Graphics g = bs.getDrawGraphics();
                render(g);
            }

            long now = System.nanoTime();
            unprocessed += (now - lastTime) / nsPerTick;
            lastTime = now;

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (shouldRender) {
                if (bs != null) {
                    bs.show();
                }
            }

            if (System.currentTimeMillis() - lastTimer1 > 1000) {
                lastTimer1 += 1000;
                fpsInfo = "FPS:" + frames + " Tick:" + tickk + " Loop:" + loop ;//+ " MousePos: " + getMousePosition();//input.mousePosition;// MouseInfo.getPointerInfo().getLocation();
             //   System.out.println(fpsInfo);
                frames = 0;
                tickk = 0;
                loop = 0;
            }
        }
    }

    
    private void tick() {
		// TODO Auto-generated method stub
    	
    
    	input.tick();
 
    	if(ui != null)
    	{
    		ui.tick();
    	}
    	else if(level != null)
    	{
    		level.tick();
    	}
    		
	}

    
    /*
    if (keys.map_up.wasReleased()) {
    	if(level.hasNorthRoom())
    	{
    		level.roomChange = Direction.NORTH;
    	}
    }
    if (keys.map_down.wasReleased()) {
    	if(level.hasSouthRoom())
    	{
    		level.roomChange = Direction.SOUTH;
    	}	
    }
    if (keys.map_left.wasReleased()) {
    	if(level.hasWestRoom())
    	{
    		level.roomChange = Direction.WEST;
    	}
    }
    if (keys.map_right.wasReleased()) {
    	if(level.hasEastRoom())
    	{
    		level.roomChange = Direction.EAST;
    	}
    		
    }
	*/
	private void render(Graphics g) {
    	// TODO Auto-generated method stub

		
		
    	g.setColor(Color.DARK_GRAY);
    	g.fillRect(0, 0, getWidth(), getHeight());
    	//System.out.println(getWidth() + " " +getHeight());
    	
    	g.translate((getWidth() - (int)(GAME_WIDTH*SCALE))/2, (getHeight() - (int)((GAME_HEIGHT+HUD_HEIGHT)*SCALE))/2);
    	//g.translate(0, 0);
    	g.clipRect(0, 0, (int)(SCREEN_WIDTH*SCALE), (int)((SCREEN_HEIGHT)*SCALE));

    
    	
    	if(ui != null) // if there's a ui, it should be focused first
    	{
    		ui.render(uiscreen);
    		g.drawImage(uiscreen.getImage(),0,0,(int)(uiscreen.width*SCALE),(int)(uiscreen.height*SCALE),null);
    	}
    	else if (level != null) 
    	{
        	level.render(screen);
        	level.renderGui(hudscreen);

        	if(debug)
        		level.renderDebug(screen);
        	
    		g.drawImage(hudscreen.getImage(), 0, 0, (int)(GAME_WIDTH*SCALE), (int)(HUD_HEIGHT*SCALE), null);	
    		g.drawImage(screen.getImage(), 0, (int)(HUD_HEIGHT*SCALE), (int)(GAME_WIDTH*SCALE), (int)(GAME_HEIGHT*SCALE), null);
    	}
    	
    	if(debug)
    	{
    		g.setFont(g.getFont().deriveFont(Font.BOLD,16));
			g.drawString(fpsInfo, 20, 20);
    	}
		

    }


	
	private void init() {
		// TODO Auto-generated method stub
		currentLevel = 1;
		if(!debug)
			ui = new IntroUi(); //new StartMenu(uiscreen.height,uiscreen.width,this);
		else
			startGame();
		
	}
	
	public void startGame()
	{
		ui = null;
		
		
		level = new Level();
		
		teemo = new Teemo(input, new Coordinate(Room.ROOM_X*Tile.WIDTH/2,Room.ROOM_Y*Tile.HEIGHT/2) , new Coordinate(15,20),level);
		
        level.createLevel(levels[currentLevel]);
        level.getCurrentRoom().addPlayerToRoom(teemo);

	}
	
	public void nextLevel()
	{
		level.getCurrentRoom().removePlayerFromRoom();
		currentLevel++;
		if(currentLevel < levels.length)
		{
			level = new Level();
			level.createLevel(levels[currentLevel]);
			teemo.position = new Coordinate(Room.ROOM_X*Tile.WIDTH/2,Room.ROOM_Y*Tile.HEIGHT/2);
			teemo.level = level;
			level.getCurrentRoom().addPlayerToRoom(teemo);
		}
		else
		{
			System.out.println("Game ended!");
			System.exit(0);
		}
	}
/*
	@Override
	public void keyPressed(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}
*/

	public void setUi(Ui ui) {
		// TODO Auto-generated method stub
		this.ui = ui;
	}

	public void restart() {
		// TODO Auto-generated method stub
		init();
	}
}
